package pl.edu.agh.uddiProxy.client;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.Text;
import com.google.gwt.xml.client.XMLParser;
import com.gwtent.acegi.client.UserLoginRpc;

public class TModelPanel extends VerticalPanel {
	private Map<String, TextBox> textBoxMap = new HashMap<String, TextBox>(); 
	private Button saveButton;
	private String tModelKey;
	private Grid infoGrid = new Grid();
	private int infoRow;
	private List<String> nameList = new ArrayList<String>();
	private List<String> valueList = new ArrayList<String>();
	private Set<Integer> wsdlSet = new HashSet<Integer>();
	private Set<TextBox> ownerSet = new HashSet<TextBox>();
	private ListBox currencyListBox;
	
	public TModelPanel(Map<String, Parameter> map) {
		Grid grid = new Grid(map.size(), 3);
		grid.getColumnFormatter().setWidth(1, "40%");
		grid.getColumnFormatter().setWidth(0, "20%");
		
		grid.setWidth("100%");
		grid.setCellSpacing(5);
		
		setWidth("100%");
		setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
		infoGrid.setCellSpacing(5);
		infoGrid.setWidth("100%");
		add(infoGrid);
		add(grid);
		
		saveButton = new Button("save");
		saveButton.addClickListener(new ClickListener() {
		
			public void onClick(Widget widget) {
				final Map<String, String> parametersMap = new HashMap<String, String>();
				for (String key : textBoxMap.keySet()) {
					if (textBoxMap.get(key).isEnabled()) {
						parametersMap.put(key, textBoxMap.get(key).getText());
					}
				}
				
				final AsyncCallback<Void> callback = new AsyncCallback<Void>() {
					
					public void onSuccess(Void arg0) {
						History.back();
					}
				
					public void onFailure(Throwable arg0) {
						Window.alert(arg0.getMessage());
					}
				};
				final SearchServiceAsync searchServiceAsync = SearchService.Util.getInstance();
				
				if (textBoxMap.get(Application.PRICE_PARAMETER).getText() != null && textBoxMap.get(Application.PRICE_PARAMETER).getText().trim().length() > 0 
						&& textBoxMap.get(Application.PRICE_PARAMETER).isEnabled()) {
					String sourceCurrency = currencyListBox.getValue(currencyListBox.getSelectedIndex());
					CurrencyService.Util.getInstance().convert(new Double(textBoxMap.get(Application.PRICE_PARAMETER).getText()), sourceCurrency, new AsyncCallback<Double>() {
						
						public void onSuccess(Double value) {
							parametersMap.put(Application.PRICE_PARAMETER, value.toString());
							searchServiceAsync.saveParameters(tModelKey, parametersMap, callback);
						}
					
						public void onFailure(Throwable caught) {
							Window.alert(caught.getMessage());
						}
					});
				} else {
					searchServiceAsync.saveParameters(tModelKey, parametersMap, callback);
				}
			}
		});
		add(saveButton);
		
		currencyListBox = new ListBox();
		fillCurrencyListBox(currencyListBox);
		currencyListBox.addChangeListener(new ChangeListener() {
		
			public void onChange(Widget widget) {
				setPrice();
			}
		});
		
		map.remove(SearchService.T_MODEL_KEY);
		int row = 0;
		int column = 0;
		for (String key : map.keySet()) {
			grid.setText(row, column++, key);
			TextBox box = new TextBox();
			textBoxMap.put(key, box);
			box.setWidth("100%");
			grid.setWidget(row, column++, box);
			grid.getCellFormatter().setHorizontalAlignment(row, column - 1, ALIGN_LEFT);
			
			if (key.equals(Application.PRICE_PARAMETER)) {
				grid.setWidget(row, column, currencyListBox);
			} else {
				grid.setText(row, column, map.get(key).getUnit());
			}
			grid.getCellFormatter().setHorizontalAlignment(row, column, ALIGN_LEFT);
			
			if (!map.get(key).isEveryone()) {
				box.setEnabled(true);
			} else if (map.get(key).isOwner()) {
				ownerSet.add(box);
			}
			
			row++;
			column = 0;
		}
	}
	
	private void fillCurrencyListBox(final ListBox box) {
		CurrencyService.Util.getInstance().getAllCurrency(new AsyncCallback<List<Currency>>() {
		
			public void onSuccess(List<Currency> list) {
				Collections.sort(list);
				String language = getLanguage().substring(0, 2);
				int i = 0;
				for (Currency currency : list) {
					box.addItem(currency.toString(), currency.getCurrencyCode());
					if (currency.getLocaleCode().equalsIgnoreCase(language)) {
						box.setSelectedIndex(i);
					}
					i++;
				}
			}
		
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}
		});
	}
	
	private void setPrice() {
		if (textBoxMap.get(Application.PRICE_PARAMETER).getText() != null && textBoxMap.get(Application.PRICE_PARAMETER).getText().trim().length() > 0) {
			String targetCurrency = currencyListBox.getValue(currencyListBox.getSelectedIndex());
			CurrencyService.Util.getInstance().convert(tModelKey, targetCurrency, new AsyncCallback<Double>() {
				
				public void onSuccess(Double value) {
					textBoxMap.get(Application.PRICE_PARAMETER).setText(value.toString());
				}
			
				public void onFailure(Throwable caught) {
					Window.alert(caught.getMessage());
				}
			});
		}
	}
	
	private void setReadOnly(final String owner) {
		UserLoginRpc.Util.getInstance().getCurrentUserName(new AsyncCallback<String>() {
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}

			public void onSuccess(final String username) {
				if (owner != null) {
					for (TextBox box : ownerSet) {
						box.setEnabled(owner.equals(username));
					}
				}
			}
		});
	}
	
	public void setTModelParameters(String tModelKey, Map<String, String> map) {
		this.tModelKey = tModelKey;
		setReadOnly(map.remove(SearchService.OWNER_KEY));
		for (String key : map.keySet()) {
			textBoxMap.get(key).setText(map.get(key));
		}
		setPrice();
		
		SearchServiceAsync searchServiceAsync = SearchService.Util.getInstance();
		searchServiceAsync.getTModelInfo(tModelKey, new AsyncCallback<String>() {
		
			public void onSuccess(String xmlString) {
				fillGrid(xmlString);
			}
		
			public void onFailure(Throwable e) {
				Window.alert(e.getMessage());
			}
		});
	}
	
	private void fillGrid(String xmlString) {
		Document document = XMLParser.parse(xmlString);
		Element rootElement = document.getDocumentElement();
		
		infoRow = 0;
		nameList.clear();
		valueList.clear();
		wsdlSet.clear();
		addRow(rootElement);
		
		infoGrid.resize(nameList.size(), 2);
		infoGrid.getColumnFormatter().setWidth(0, "20%");
		
		infoGrid.setText(0, 0, "TModelKey");
		infoGrid.setText(0, 1, tModelKey);
		for (int i = 0; i < nameList.size(); i++) {
			infoGrid.setText(i + 1, 0, nameList.get(i));
			if (wsdlSet.contains(i)) {
				final String url = valueList.get(i);
				Hyperlink hyperlink = new Hyperlink(url, "download=" + url);
				hyperlink.addClickListener(new ClickListener() {
				
					public void onClick(Widget widget) {
						downloadWSDL(url);
					}
				});
				infoGrid.setWidget(i + 1, 1, hyperlink);
			} else {
				infoGrid.setText(i + 1, 1, valueList.get(i));
			}
		}
	}
	
	private void downloadWSDL(final String url) {
		SearchServiceAsync searchServiceAsync = SearchService.Util.getInstance();
		searchServiceAsync.downloadWSDL(tModelKey, new AsyncCallback<Void>() {
		
			public void onSuccess(Void arg0) {
				Window.open(url, "_blank", "");
			}
		
			public void onFailure(Throwable arg0) {
				Window.alert(arg0.getMessage());
			}
		});
	}
	
	private void addRow(Element element) {
		if (element.getNodeName().equals("xml-fragment")) {
			for (int i = 0; i < element.getChildNodes().getLength(); i++) {
				addRow((Element) element.getChildNodes().item(i));
			}
		} else if (element.hasChildNodes()) {
			String name = element.getNodeName();
			if (name.indexOf(":") > 0) {
				name = name.substring(name.indexOf(":") + 1);
			}
			if (element.getNodeName().equals("urn:overviewDoc")) {
				
				for (int i = 0; i < element.getChildNodes().getLength(); i++) {
					Element e = (Element) element.getChildNodes().item(i);
					if (e.getAttribute("useType") != null) {
						String type = e.getAttribute("useType");
						if (type.equals("wsdlInterface")) {
							wsdlSet.add(infoRow);
						}
					}
					nameList.add(name);
					valueList.add(((Text) e.getFirstChild()).getData());
					infoRow++;
				}
			} else if (element.getNodeName().equals("urn:categoryBag")) {
				StringBuffer nameBuffer = new StringBuffer();
				for (int i = 0; i < element.getChildNodes().getLength(); i++) {
					Element e = (Element) element.getChildNodes().item(i);
					if (nameBuffer.length() > 0) {
						nameBuffer.append(", ");
					}
					String[] s = e.getAttribute("tModelKey").split(":");
					nameBuffer.append(s[s.length - 1]);
					nameBuffer.append(" = ");
					nameBuffer.append(e.getAttribute("keyValue"));
				}
				nameList.add(name);
				valueList.add(nameBuffer.toString());
				infoRow++;
				
			} else if (element.getFirstChild().getNodeName().equals("#text")) {
				
				if (element.getAttribute("useType") != null) {
					String type = element.getAttribute("useType");
					if (type.equals("wsdlInterface")) {
						wsdlSet.add(infoRow);
					}
				}
				nameList.add(name);
				valueList.add(((Text) element.getFirstChild()).getData());
				infoRow++;
			} else {
				nameList.add(name);
				valueList.add("");
				infoRow++;
				
				for (int i = 0; i < element.getChildNodes().getLength(); i++) {
					addRow((Element) element.getChildNodes().item(i));
				}
			}				
		}
	}
	
	public static native String getLanguage() /*-{
	    if (navigator.language == null) {
		    if (navigator.userLanguage == null) {
		    	return "";
		    }
		    else {
		    	return navigator.userLanguage;
		    }
	    } else {
		    return navigator.language;
	    }
	}-*/;
}
